#include <rtgui/font_freetype.h>

#ifdef RTGUI_USING_TTF
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>

static void rtgui_freetype_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const char* text, rt_ubase_t len, struct rtgui_rect* rect);
static void rtgui_freetype_font_get_metrics(struct rtgui_font* font, const char* text, rtgui_rect_t* rect);

struct rtgui_font_engine freetype_font_engine =
{
	RT_NULL,
	RT_NULL,
	rtgui_freetype_font_draw_text,
	rtgui_freetype_font_get_metrics
};

struct rtgui_freetype_font
{
	int bold;
	int italic;

	FT_Face     face;
	FT_Library  library;
};

static void gbk_to_unicode(rt_uint16_t *unicode, const unsigned char *text, int len)
{
	int i;
	unsigned short wch;
	extern unsigned short ff_convert(unsigned short wch, int direction);

	for (i = 0; i < len; )
	{
		if (*text < 0x80)
		{
			wch = *text;
			*unicode = ff_convert(wch, 1);
			text ++;
			i ++;
		}
		else
		{
			wch = wch = *(text + 1) | (*text << 8);
			*unicode = ff_convert(wch, 1);
			text += 2;
			i += 2;
		}

		unicode ++;
	}

	*unicode = '\0';
}

static void rtgui_freetype_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const char* text, rt_ubase_t len, struct rtgui_rect* rect)
{
	int index = 0;
	FT_Error err = 0;
	rt_uint16_t *text_short, *text_ptr;
	struct rtgui_freetype_font* freetype;

	RT_ASSERT(font != RT_NULL);
	freetype = (struct rtgui_freetype_font*) font->data;
	RT_ASSERT(freetype != RT_NULL);

	/* allocate unicode buffer */
	text_short = (rt_uint16_t*)rtgui_malloc((len + 1)* 2);
	if (text_short == RT_NULL) return ; /* out of memory */

	/* convert gbk to unicode */
	gbk_to_unicode(text_short, text, len);
	text_ptr = text_short;

	while (*text_ptr)
	{
		index = FT_Get_Char_Index(freetype->face, *text_ptr);
		err = FT_Load_Glyph(freetype->face, index, FT_LOAD_DEFAULT|FT_LOAD_RENDER);
		if (err == 0)
		{
			int rows, x;
			rt_uint8_t* ptr;

			/* render font */
			ptr = (rt_uint8_t*)freetype->face->glyph->bitmap.buffer;
			
			for (rows = 0; rows < freetype->face->glyph->bitmap.rows; rows ++)
				for (x = 0; x < freetype->face->glyph->bitmap.width; x++)
				{
					if (*ptr > 0)
						rtgui_dc_draw_color_point(dc, rect->x1 + x, rect->y1 + rows, RTGUI_RGB(0xff - *ptr, 0xff - *ptr, 0xff - *ptr));
					ptr ++;
				}
		}

		text_ptr ++;
		rect->x1 += freetype->face->glyph->bitmap.width;
	}

	/* release unicode buffer */
	rtgui_free(text_short);
}

static void rtgui_freetype_font_get_metrics(struct rtgui_font* font, const char* text, rtgui_rect_t* rect)
{
	int index = 0, len;
	FT_Error err = 0;
	rt_uint16_t w = 0, h = 0;
	rt_uint16_t *text_short, *text_ptr;
	struct rtgui_freetype_font* freetype;
	
	RT_ASSERT(font != RT_NULL);
	RT_ASSERT(rect != RT_NULL);
	freetype = (struct rtgui_freetype_font*) font->data;
	RT_ASSERT(freetype != RT_NULL);

	len = strlen(text);
	memset(rect, 0, sizeof(struct rtgui_rect));

	/* allocate unicode buffer */
	text_short = (rt_uint16_t*)rtgui_malloc((len + 1)* 2);
	if (text_short == RT_NULL) return ; /* out of memory */

	/* convert gbk to unicode */
	gbk_to_unicode(text_short, text, len);
	text_ptr = text_short;

	while (*text_ptr)
	{
		index = FT_Get_Char_Index(freetype->face, *text_ptr);
		err = FT_Load_Glyph(freetype->face, index, FT_LOAD_DEFAULT);

		if (err == 0)
		{
			w += freetype->face->glyph->bitmap.width;
			if (freetype->face->glyph->bitmap.rows > h)
			{
				h = freetype->face->glyph->bitmap.rows;
			}
		}

		text_ptr ++;
	}

	rect->x1 = 0; rect->y1 = 0;
	rect->x2 = w; rect->y2 = h;

	/* release unicode buffer */
	rtgui_free(text_short);
}

rtgui_font_t* rtgui_freetype_font_create(const char* filename, int bold, int italic, rt_size_t size)
{
	FT_Error err = 0;
	struct rtgui_font* font;

	font = (struct rtgui_font*) rtgui_malloc (sizeof(struct rtgui_font));
	if (font != RT_NULL)
	{
		struct rtgui_freetype_font* freetype;

		freetype = (struct rtgui_freetype_font*) rtgui_malloc (sizeof(struct rtgui_freetype_font));
		if (freetype == RT_NULL)
		{
			rt_free(font);
			font = RT_NULL;
		}
		else
		{
			err = FT_Init_FreeType(&freetype->library);
			if((err = FT_New_Face(freetype->library, filename, 0, &freetype->face)))
			{
				FT_Done_FreeType(freetype->library);

				rt_free(font);
				font = RT_NULL;
			}
			else
			{
				err = FT_Select_Charmap(freetype->face, ft_encoding_unicode);
				if(err)
				{
					err = FT_Select_Charmap(freetype->face, ft_encoding_latin_1 );
				}

				err = FT_Set_Pixel_Sizes(freetype->face, 0, size);
				if (err != 0)
				{
					rtgui_free(font);
					font = RT_NULL;

					FT_Done_FreeType(freetype->library);
					rtgui_free(freetype);

					return RT_NULL;
				}

				freetype->bold = bold;
				freetype->italic = italic;

				rt_kprintf("fonfile:%s\n", filename);
				rt_kprintf("font family_name:%s\n", freetype->face->family_name);
				rt_kprintf("font style_name:%s\n", freetype->face->style_name);

				/* set user data */
				font->data = freetype;
				font->family = rt_strdup(freetype->face->family_name);
				font->height = (rt_uint16_t)size;
				font->refer_count = 0;
				font->engine = &freetype_font_engine;

				/* add to system */
				rtgui_font_system_add_font(font);
			}
		}
	}

	return font;
}

void rtgui_freetype_font_destroy(rtgui_font_t* font)
{
	struct rtgui_freetype_font* freetype;
	
	RT_ASSERT(font != RT_NULL);
	freetype = (struct rtgui_freetype_font*) font->data;
	RT_ASSERT(freetype != RT_NULL);

	rtgui_font_system_remove_font(font);

	FT_Done_Face    (freetype->face);
	FT_Done_FreeType(freetype->library);
	rtgui_free(freetype);
	rtgui_free(font);
}
#endif
